//@author A0087652W
package net.mysoc.w111j.service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import net.mysoc.w111j.model.BadCategoryNameException;
import net.mysoc.w111j.model.BadPaymentTypeNameException;
import net.mysoc.w111j.model.Category;
import net.mysoc.w111j.model.Expense;
import net.mysoc.w111j.model.Money;
import net.mysoc.w111j.model.PaymentType;
import net.mysoc.w111j.ui.Constants;
import net.mysoc.w111j.ui.expenselist.ExpenseListPresenter;
import net.mysoc.w111j.ui.main.MainPresenter;

/**
 * This class is used to perform the command line function.
 * The command input must match the format as the syntax written below
 */
public class CommandService {
    private MainPresenter mainPresenter;
    private ExpenseListPresenter expenseListPresenter;
    private ExpenseService expenseService;

    public void setMainPresenter(MainPresenter mainPresenter) {
        this.mainPresenter = mainPresenter;
    }

    public void setExpenseListPresenter(ExpenseListPresenter expenseListPresenter) {
        this.expenseListPresenter=expenseListPresenter;
    }

    public void setExpenseService(ExpenseService expenseService) {
        this.expenseService = expenseService;
    }
    public void parseCommand(String command) {
        command = command.trim();
        if(command.matches("add expense .*")){
            try{
                //syntax:add expense name=abc&&description=&&price=5&&category=food&&paymentType=cash&&date=3 Apr 2013
                String input=command.substring(12);
                String[]expression=input.split("&&");
                String name=expression[0].split("=")[1];
                //allow the null input from user for the description
                String description="";
                try{
                    description=expression[1].split("=")[1];
                }catch(ArrayIndexOutOfBoundsException ae){
                    description="";
                }
                //price and name and category can't be null
                String price=expression[2].split("=")[1];
                String category=expression[3].split("=")[1];
                Category cat = expenseService.getCategoryByName(category);
                String paymentType=expression[4].split("=")[1];
                PaymentType pt = expenseService.getPaymentTypeByName(paymentType);
                //date must follow the format as below
                String date="";
                SimpleDateFormat df = Constants.DATE_FORMAT;
                try{
                    date=expression[5].split("=")[1];
                }catch(ArrayIndexOutOfBoundsException ae2){
                    date=df.format(new Date());
                }
                Date d=null;
                String today=df.format(new Date());
                Date current=new Date();
                try {
                    current=df.parse(today);
                    d = df.parse(date);
                    if(d.after(current)){
                        return;
                    }
                } catch (ParseException e) {
                    return;
                }
                if (cat == null || pt == null) {
                    return;
                }
                expenseService.updateExpense(new Expense(-1,name,description,new Money(price),cat, pt,d));
            }catch(Exception exception){}
        }
        else if(command.matches("add category name=.*")){
            //syntax: add category name=food
            //name can't be null and can't be the same
            try {
                String input=command.substring(18);
                expenseService.updateCategory(new Category(-1, input));
            } catch (BadCategoryNameException ne) {}
        }
        else if(command.matches("add paymentType name=.*")){
            //syntax: add paymentType name=cash
            //name can't be null and can't be the same
            try {
                String input=command.substring(21);
                expenseService.updatePaymentType(new PaymentType(-1,input));
            } catch (BadPaymentTypeNameException e) {}
        }
        else if(command.matches("update expense id=.*")){
            try{
                //syntax:update expense id=5&&name=abc&&description=null&&price=5&&category=food&&paymentType=cash&&date=3 Apr 2013
                String input=command.substring(15);
                if(input.contains("&&")){
                    String[]expression=input.split("&&");
                    String id=expression[0].split("=")[1];
                    int expenseId = Integer.parseInt(id);
                    Expense oldExpense = expenseService.getExpense(expenseId);
                    if (oldExpense != null) {
                        Expense e = new Expense(oldExpense.getId(), oldExpense.getName(), oldExpense.getDetails(),
                                oldExpense.getPrice(), oldExpense.getCategory(), oldExpense.getPaymentType(),
                                oldExpense.getDate());
                        for(int i=1;i<expression.length;i++){
                            if(expression[i].split("=")[0].equalsIgnoreCase("name")){
                                String name=expression[i].split("=")[1];
                                e.setName(name);
                            }
                            else if(expression[i].split("=")[0].equalsIgnoreCase("description")){
                                String description="";
                                try{
                                    description=expression[i].split("=")[1];
                                }catch(ArrayIndexOutOfBoundsException ae){
                                    description="";
                                }
                                e.setDetails(description);
                            }
                            else if(expression[i].split("=")[0].equalsIgnoreCase("price")){
                                String price=expression[i].split("=")[1];
                                e.setPrice(new Money(price));
                            }
                            else if(expression[i].split("=")[0].equalsIgnoreCase("category")){
                                String category=expression[i].split("=")[1];

                                Category cat = expenseService.getCategoryByName(category);
                                if (cat == null) return;
                                e.setCategory(cat);
                            }
                            else if(expression[i].split("=")[0].equalsIgnoreCase("paymentType")){
                                String paymentType=expression[i].split("=")[1];

                                PaymentType pt = expenseService.getPaymentTypeByName(paymentType);
                                if (pt == null) return;
                                e.setPaymentType(pt);
                            }
                            else if(expression[i].split("=")[0].equalsIgnoreCase("date")){
                                String date="";
                                SimpleDateFormat df = Constants.DATE_FORMAT;
                                try{
                                    date=expression[i].split("=")[1];
                                }catch(ArrayIndexOutOfBoundsException ae2){
                                    date=df.format(new Date());
                                }
                                Date d=null;
                                String today=df.format(new Date());
                                Date current=new Date();
                                try {
                                    current=df.parse(today);
                                    d = df.parse(date);
                                    if(d.after(current)){
                                        d=current;
                                    }
                                } catch (ParseException ex) {
                                    return;
                                }
                                e.setDate(d);
                            }
                        }
                        expenseService.updateExpense(e);
                    }
                }
            }catch(Exception exception){}
        }
        else if(command.matches("update category .*")){
            //syntax:update category oldName=abc&&newName=def
            //name can't be null
            try{
                String input=command.substring(16);
                String[]expression=input.split("&&");
                String oldName=expression[0].split("=")[1];
                String newName=expression[1].split("=")[1];
                Category oldCat = expenseService.getCategoryByName(oldName);
                Category newCat = new Category(oldCat.getId(),newName);
                expenseService.updateCategory(newCat);
            }catch(Exception exception){}
        }
        else if(command.matches("update paymentType .*")){
            //syntax:update paymentType oldName=cash&&newName=card
            try{
                String input=command.substring(19);
                String[]expression=input.split("&&");
                String oldName=expression[0].split("=")[1];
                String newName=expression[1].split("=")[1];
                PaymentType oldPt = expenseService.getPaymentTypeByName(oldName);
                PaymentType newPt = new PaymentType(oldPt.getId(),newName);
                expenseService.updatePaymentType(newPt);
            }catch(Exception exception){}
        }
        else if(command.matches("delete expense id=.*")){
            //syntax: delete expense id=20
            try{
                String input=command.substring(18);
                int id = Integer.parseInt(input);
                Expense e = expenseService.getExpense(id);
                if (e != null) {
                    expenseService.deleteExpense(id);
                }
            }catch(Exception exception){}
        }
        else if(command.matches("delete category name=.*")){
            //syntax: delete category name=food
            try{
                String input=command.substring(21);
                Category c = expenseService.getCategoryByName(input);
                if (c != null) {
                    expenseService.deleteCategory(c.getId());
                }
            }catch(Exception exception){}
        }
        else if(command.matches("delete paymentType name=.*")){
            //syntax: delete paymentType name=cash
            try{
                String input=command.substring(24);
                PaymentType pt = expenseService.getPaymentTypeByName(input);
                if (pt != null) {
                    expenseService.deletePaymentType(pt.getId());
                }
            }catch(Exception exception){}
        }
        else if(command.matches("set budget=.*")){
            //syntax: set budget=500
            try{
                String input=command.substring(11);
                expenseService.setBudget(new Money(input));
            }catch(NumberFormatException e){
            }
        }
        else if(command.matches("generate.*")){
            //syntax: generate report
            this.mainPresenter.handleGenerateReport();
        }
        else if(command.matches("search input=.*")){
            //search input=abc
            try{
                String input=command.substring(13);
                if (input.trim().isEmpty()) {
                    this.expenseListPresenter.handleAllCategories();
                } else {
                    this.expenseListPresenter.handleSearchBoxInput(input);
                }
            }catch(Exception exception){}
        }
        else if(command.matches("view expenses")){
            //syntax: view expenses
            this.expenseListPresenter.handleAllCategories();
        }
        else if(command.matches("undo")){
            //syntax:undo
            try{
                expenseService.undo();
            }catch(Exception exception){}
        }
    }
}
